package org.springframework.extcache.localcache;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.annotation.Order;
import org.springframework.extcache.AbstractCacheManager;
import org.springframework.extcache.ConfigurableCache;
import org.springframework.extcache.localcache.ConcurrentMapCache.CacheObject;

@Order(10)
public class ConcurrentMapCacheManager extends AbstractCacheManager implements DisposableBean {

  private ConcurrentMap<String, Object> store;
  private int                           maxSize;
  private Thread                        expireChecker;

  ConcurrentMapCacheManager() {
  }

  public ConcurrentMapCacheManager(ConcurrentMap<String, Object> store, int maxSize) {
    this.maxSize = maxSize;
    this.store = store;
    expireChecker = new Thread(new ExpireChecker(), "ExpireChecker");
    expireChecker.setDaemon(true);
    expireChecker.start();
  }

  @Override
  public Collection<String> getCacheNames() {
    return store.keySet();
  }

  @Override
  public boolean isFused() {
    return false;
  }

  class ExpireChecker implements Runnable {

    private void removeExpiredCache() {
      for (Iterator<Map.Entry<String, Object>> itr = store.entrySet().iterator(); itr.hasNext();) {
        Entry<String, Object> entity = itr.next();
        Object cacheObjectValue = entity.getValue();
        if (cacheObjectValue instanceof CacheObject) {
          CacheObject cacheObject = (CacheObject) cacheObjectValue;
          if ((cacheObject.getCreateTime().getTime() + getExpireTime() * 1000) < System.currentTimeMillis()) {
            itr.remove();
          }
        }
      }
    }

    @Override
    public void run() {
      while (true) {
        removeExpiredCache();
        try {
          Thread.sleep(5000);// 5s检查一次过期
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  @Override
  public void destroy() throws Exception {
    expireChecker.interrupt();
  }

  @Override
  protected ConfigurableCache doGetCache(String name) {
    boolean isPutable = store.size() < maxSize;
    ConfigurableCache cache = new ConcurrentMapCache(name, store, isPutable);
    cache.setCacheManager(this);
    return cache;
  }
}
